//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
// 

#include "RoundRobinScheduler.h"

Define_Module(RoundRobinScheduler)

#ifdef _PREV_

bool RoundRobinScheduler::receivePacket(NetPacket* packet, int gn){

	int src = packet->getSrc();

	bool find = 0;
	int num = -1;
	// przeszukanie czy istnieje kolejka do adresu
	for( std::list<int>::iterator iter = srcList.begin(); !find && iter != srcList.end(); ++iter)
	{
		num++;
		find = (*iter) == src;
	}
	// znaleziono
	if(find){
		std::list<list<NetPacket*>*>::iterator element = packetList.begin();
		while(num-- > 0) element++;
		(*element)->push_back(packet);
		packetSum++;
	}else{
	// nie znaleziono, dodanie adresu
		srcList.push_back(src);
		packetList.push_back(new std::list<NetPacket* >());
		packetList.back()->push_back(packet);
		packetSum++;
	}
	return true;
}


NetPacket* RoundRobinScheduler::getPacketForDeparture(){
	NetPacket* ref;
	if(packetSum > 0){
		std::list<list<NetPacket*>*>::iterator element = packetList.begin();
		++currentQueue;
		if(currentQueue >= srcList.size()) {
			currentQueue = 0;
			element = packetList.begin();
		}else{
			int cq = currentQueue;
			while(cq-- > 0) element++;
		}
		while( (*element)->empty()){
			element++;
			currentQueue++;
			if(currentQueue >= srcList.size()) {
				currentQueue = 0;
				element = packetList.begin();
			}
		}
		ref = (*element)->front();
		(*element)->pop_front();
		packetSum--;
	}
	return ref;
}

#else

#ifdef _PREV2_

bool RoundRobinScheduler::receivePacket(NetPacket* packet, int gn){

	int prio = packet->getPriority();

	bool find = 0;
	int num = -1;
	// przeszukanie czy istnieje kolejka do adresu
	for( std::list<int>::iterator iter = priorList.begin(); !find && iter != priorList.end(); ++iter)
	{
		num++;
		find = (*iter) == prio;
	}
	// znaleziono
	if(find){
		std::list<list<NetPacket*>*>::iterator element = packetList.begin();
		while(num-- > 0) element++;
		(*element)->push_back(packet);
		packetSum++;
	}else{
	// nie znaleziono
		priorList.push_back(prio);
		packetList.push_back(new std::list<NetPacket* >());
		packetList.back()->push_back(packet);
		packetSum++;
	}
	return true;
}

#else

bool RoundRobinScheduler::receivePacket(NetPacket* packet, int gn){

	int prio = packet->getPriority();

	int num = 0;
	// przeszukanie czy istnieje kolejka do adresu
	for( std::list<int>::iterator iter = priorList.begin(); (*iter) < prio && iter != priorList.end(); ++iter)
		num++;
	// znaleziono
	std::list<list<NetPacket*>*>::iterator element = packetList.begin();
	while(num-- > 0) element++;
	(*element)->push_back(packet);
	packetSum++;

	return true;
}


#endif


NetPacket* RoundRobinScheduler::getPacketForDeparture(){
	NetPacket* ref;
	if(packetSum > 0){
		std::list<list<NetPacket*>*>::iterator element = packetList.begin();
		++currentQueue;
		if(currentQueue >= priorList.size()) {
			currentQueue = 0;
			element = packetList.begin();
		}else{
			int cq = currentQueue;
			while(cq-- > 0) element++;
		}
		while( (*element)->empty()){
			element++;
			currentQueue++;
			if(currentQueue >= priorList.size()) {
				currentQueue = 0;
				element = packetList.begin();
			}
		}
		ref = (*element)->front();
		(*element)->pop_front();
		packetSum--;
	}
	return ref;
}





#endif

void RoundRobinScheduler::initialize(){
	AbstractScheduler::initialize();
	packetSum = 0;
	currentQueue = -1;
	WATCH(packetSum);
	WATCH(currentQueue);
	WATCH_LIST(priorList);
	maxQueueSize = par("maxQueueSize");
#ifndef _PREV2_
#ifndef _PREV_

	int ql = par("queueLength");
	int max = par("maxPriority");
	if(ql > max) ql = max;
	double up = (double)max/(double)ql;
	for(int i = 0; i < ql-1; i++)
	{
		priorList.push_back((int)((i+1)*up));
		packetList.push_back(new std::list<NetPacket* >());
	}
	packetList.push_back(new std::list<NetPacket* >());
	priorList.push_back(1000);

#endif
#endif
}

bool RoundRobinScheduler::hasPacketsAwaitingDeparture(){
	return packetSum>0 && packetSum < maxQueueSize;
}
